/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-03-10     Hao       the first version
 */
#include <hardware/can_operate.h>
#include <string.h>

// 上位机
can_t can_dev =
{
   .dev = RT_NULL,
   .name = "can1",
   .baud_rate = CAN500kBaud,
   .rx_sem = RT_NULL
};

static rt_sem_t can1_rx_sem = RT_NULL;
static rt_err_t can1_rx_callback(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(can1_rx_sem);
    return RT_EOK;
}

int can_operate_init(can_ptr port_ptr)
{
    rt_err_t ret = RT_EOK;

    // 查找相应的CAN口
    port_ptr->dev = rt_device_find(port_ptr->name);
    RT_ASSERT(port_ptr->dev != RT_NULL);

    // 设置波特率
    ret = rt_device_control(port_ptr->dev, RT_CAN_CMD_SET_BAUD, (void *)port_ptr->baud_rate);
    RT_ASSERT(ret == RT_EOK);

    // 创建信号量
    can1_rx_sem = rt_sem_create("can1_rx_sem", 0, RT_IPC_FLAG_PRIO);
    RT_ASSERT(can1_rx_sem != RT_NULL);
    port_ptr->rx_sem = can1_rx_sem;

    // 设置回调函数
    ret = rt_device_set_rx_indicate(port_ptr->dev, can1_rx_callback);
    RT_ASSERT(ret == RT_EOK);

#ifdef RT_CAN_USING_HDR     // TODO:这里可以直接过滤掉跟本电机无关的消息
    //只过滤1位，其他的依次类推
    struct rt_can_filter_item items[] =
    {
        {(0x12020100), 1, 0, 0, ((0x000000ff<< 3) | 4), 0},
    };
    struct rt_can_filter_config cfg = {1, 1, items};
    ret = rt_device_control(can_dev.dev, RT_CAN_CMD_SET_FILTER, &cfg);
#endif

    // 打开方式，默认设置为中断发送和中断接收
    ret = rt_device_open(port_ptr->dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
    RT_ASSERT(ret == RT_EOK);

    return 0;
}

rt_size_t can_send(can_ptr port_ptr, rt_uint32_t dst_id, rt_uint8_t *buf, rt_uint8_t len)
{
    rt_size_t size;

    // 打包一个CAN数据包
    struct rt_can_msg temp_tx_msg = {0};
    temp_tx_msg.id = dst_id;                /* ID */
    temp_tx_msg.ide = RT_CAN_STDID;         /* 标准格式 */
    temp_tx_msg.rtr = RT_CAN_DTR;           /* 数据帧 */
    temp_tx_msg.len = (len <= 8) ? len : 8; /* 数据长度最长为 8 */
    rt_memcpy(temp_tx_msg.data, buf, len);

    // 发送出去
    size = rt_device_write(port_ptr->dev, 0, &temp_tx_msg, sizeof(struct rt_can_msg));

    return size;
}

rt_size_t can_recv(can_ptr port_ptr, rt_uint32_t *src_id, rt_uint8_t *buf, rt_uint8_t *len)
{
    rt_size_t size;

    // 接收一个CAN数据包
    struct rt_can_msg temp_rx_msg = {0};
    size = rt_device_read(port_ptr->dev, 0, &temp_rx_msg, sizeof(struct rt_can_msg));

    // 解析出来
    *src_id = temp_rx_msg.id;
    *len = temp_rx_msg.len;
    rt_memcpy(buf, temp_rx_msg.data, temp_rx_msg.len);

    return size;
}

#if 0

void can_test()
{
    rt_err_t ret;
    rt_uint32_t src_id;
    uint8_t len;
    uint8_t buf[8] = {0};

    while(1)
    {
        ret = rt_sem_take(can_dev.rx_sem, RT_WAITING_FOREVER);
        if (ret == RT_EOK)
        {
            can_recv(&can_dev, &src_id, buf, &len);
            can_send(&can_dev, src_id, buf, len);
            rt_memset(buf, 0, len);
        }
    }
}

MSH_CMD_EXPORT(can_test, can_test);
#endif
